package dao

import (
	"activity_srv/basic/config"
	__ "activity_srv/basic/proto"
	"errors"
	"fmt"
	"math/rand"
	"time"
	"activity_srv/handler/models"
)

// CreateGroupBuying 创建拼团
func CreateGroupBuying(in *__.CreateGroupPReq) (*__.CreateGroupPResp, error) {
	// 参数验证
	if in.UserId <= 0 {
		return nil, errors.New("用户ID不能为空")
	}
	if in.GroupGid <= 0 {
		return nil, errors.New("拼团商品ID不能为空")
	}
	if in.Num <= 0 {
		return nil, errors.New("购买数量必须大于0")
	}

	// 开启数据库事务
	tx := config.DB.Begin()
	if tx.Error != nil {
		return nil, fmt.Errorf("开启事务失败: %v", tx.Error)
	}
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	// 定义统一的事务回滚和错误处理函数
	rollbackWithError := func(message string, err error) (*__.CreateGroupPResp, error) {
		tx.Rollback()
		return nil, fmt.Errorf("%s: %v", message, err)
	}

	// 1. 验证商品是否存在且有效
	var groupPGoods models.GroupPGoods
	if err := tx.Where("id = ?", in.GroupGid).First(&groupPGoods).Error; err != nil {
		return rollbackWithError("拼团商品不存在", err)
	}

	// 2. 验证用户是否有作为团长的资格
	var user models.User
	user.Id = uint32(in.UserId)
	if err := user.GetUserInfoById(); err != nil {
		return rollbackWithError("获取用户信息失败", err)
	}

	// 2.1 检查用户状态是否正常
	if user.UStatus != 1 {
		return rollbackWithError("账号状态异常，无法创建拼团", nil)
	}

	// 2.2 检查用户等级是否满足团长最低要求
	if groupPGoods.MinLeaderLevel > 0 && user.UserLevel < groupPGoods.MinLeaderLevel {
		return rollbackWithError(fmt.Sprintf("团长等级要求%d级，您当前%d级", groupPGoods.MinLeaderLevel, user.UserLevel), nil)
	}

	// 2.3 检查用户信用分是否满足团长最低要求
	if groupPGoods.MinCreditScore > 0 && user.CreditScore < groupPGoods.MinCreditScore {
		return rollbackWithError(fmt.Sprintf("团长信用分要求%d分，您当前%d分", groupPGoods.MinCreditScore, user.CreditScore), nil)
	}

	// 2.4 检查用户当前同时进行中的拼团数量是否超过限制
	concurrentGroupsCount, err := models.GetUserActiveGroupsCountWithTx(tx, uint64(in.UserId))
	if err != nil {
		return rollbackWithError("获取用户拼团数量失败", err)
	}
	if concurrentGroupsCount >= int64(groupPGoods.MaxConcurrentGroups) {
		return rollbackWithError(fmt.Sprintf("您当前已创建%d个拼团，最多只能同时创建%d个拼团", concurrentGroupsCount, groupPGoods.MaxConcurrentGroups), nil)
	}

	// 3. 检查商品库存
	if groupPGoods.Stock < uint64(in.Num) {
		return rollbackWithError("商品库存不足", nil)
	}

	// 4. 生成拼团ID和订单号
	groupNum := GenerateGroupNum()
	personalOrderNo, _, _ := GenerateOrderNo(in.UserId)
	groupOrderNo := GenerateGroupOrderNo(groupNum)

	// 5. 创建拼团记录
	now := time.Now()
	var expireTime time.Time
	var people uint64
	var price float64
	var groupType uint8 = 0 // 默认是普通拼团

	// 根据拼团类型设置不同的参数
	if in.GroupType > 0 {
		groupType = 1                           // 超级拼团
		expireTime = now.Add(48 * time.Hour)    // 超级拼团有效期48小时
		people = uint64(groupPGoods.People * 2) // 超级拼团人数是普通拼团的2倍
		price = groupPGoods.PingPrice * 0.8     // 超级拼团价格是普通拼团的8折
	} else {
		expireTime = now.Add(24 * time.Hour) // 普通拼团有效期24小时
		people = uint64(groupPGoods.People)  // 普通拼团人数
		price = groupPGoods.PingPrice        // 普通拼团价格
	}

	// 生成邀请码
	inviteCode, err := GetGroupInvitationCode(in.UserId, 0) // 这里第二个参数可以先用0，后面会被实际ID覆盖
	if err != nil {
		return rollbackWithError("生成邀请码失败", err)
	}

	groupBuying := models.GroupBuying{
		UserId:         uint64(in.UserId),
		TotalNum:       uint64(in.Num),
		GroupNum:       groupNum,
		PersonGroupNum: groupOrderNo,
		TotalPrice:     price * float64(in.Num),
		GroupGid:       uint64(in.GroupGid),
		People:         people,
		Price:          price,
		StartTime:      now.Format("2006-01-02 15:04:05"),
		EndTime:        expireTime.Format("2006-01-02 15:04:05"),
		KId:            0, // 0表示团长
		Status:         1, // 1表示进行中
		InviteCode:     inviteCode,
		GroupType:      groupType, // 拼团类型
	}

	if err := tx.Create(&groupBuying).Error; err != nil {
		return rollbackWithError("创建拼团失败", err)
	}

	// 6. 扣减库存
	groupPGoods.Stock -= uint64(in.Num)
	if err := groupPGoods.UpdateStock(); err != nil {
		return rollbackWithError("扣减库存失败", err)
	}

	// 提交事务
	if err := tx.Commit().Error; err != nil {
		return rollbackWithError("提交事务失败", err)
	}

	// 事务成功后，使用实际的拼团ID重新生成邀请码并更新
	if groupBuying.Id > 0 {
		actualInviteCode, err := GetGroupInvitationCode(in.UserId, int64(groupBuying.Id))
		if err == nil {
			err := groupBuying.UpdateByInviteCode(actualInviteCode)
			if err != nil {
				return nil, fmt.Errorf("更新邀请码失败: %v", err)
			}
		}
	}

	return &__.CreateGroupPResp{
		Message:         "创建拼团成功",
		GroupId:         int64(groupBuying.Id),
		PersonalOrderNo: personalOrderNo,
		GroupOrderNo:    groupOrderNo,
	}, nil
}

// GenerateGroupNum 生成拼团编号
func GenerateGroupNum() string {
	now := time.Now()
	return fmt.Sprintf("GP%d%d%d%d%d%d%d",
		now.Year(), now.Month(), now.Day(),
		now.Hour(), now.Minute(), now.Second(),
		rand.Intn(10000))
}

// GenerateGroupOrderNo 生成拼团公共订单号
func GenerateGroupOrderNo(groupNum string) string {
	return fmt.Sprintf("GO%s", groupNum)
}

// JoinGroupBuying 参与拼团
func JoinGroupBuying(in *__.JoinGroupPReq) (*__.JoinGroupPResp, error) {
	// 1. 验证拼团是否存在且有效
	var group models.GroupBuying
	group.GroupNum = in.GroupOrderNo
	if err := group.GetGroupNumById(); err != nil {
		return nil, errors.New("拼团不存在或已结束")
	}

	// 2. 检查拼团是否已过期
	now := time.Now()
	endTime, _ := time.Parse("2006-01-02 15:04:05", group.EndTime)
	if now.After(endTime) {
		// 更新拼团状态为未完成
		err := UpdateGroupStatus(in.GroupOrderNo, 3)
		if err != nil {
			return nil, errors.New("更新拼团状态失败")
		}
		return nil, errors.New("拼团已过期")
	}

	// 3. 检查拼团人数是否已满 - 考虑拼团类型
	var count int64
	if err := group.GetGroupCount(count); err != nil {
		return nil, errors.New("获取拼团人数失败")
	}
	// 根据拼团类型使用正确的人数限制
	if count >= int64(group.People) {
		return nil, errors.New("拼团人数已满")
	}

	//
	var exists int64
	if err := group.GetGroupPByUserId(exists); err != nil {
		return nil, errors.New("获取拼团人数失败")
	}
	if exists > 0 {
		return nil, errors.New("您已经在该拼团中")
	}

	// 5. 获取拼团商品信息
	var groupPGoods models.GroupPGoods
	groupPGoods.Id = group.GroupGid
	if err := group.GetGroupPGById(); err != nil {
		return nil, errors.New("拼团商品不存在")
	}

	// 6. 检查商品库存
	if groupPGoods.Stock < uint64(in.Num) {
		return nil, errors.New("商品库存不足")
	}

	// 7. 生成个人订单号
	personalOrderNo, _, _ := GenerateOrderNo(in.UserId)
	groupOrderNo := GenerateGroupOrderNo(in.GroupOrderNo)

	// 8. 创建拼团记录
	// 对于超级拼团，使用超级拼团的价格
	price := groupPGoods.PingPrice
	if group.GroupType == 1 {
		price = groupPGoods.PingPrice * 0.8
	}

	joinGroup := models.GroupBuying{
		UserId:         uint64(in.UserId),
		TotalNum:       uint64(in.Num),
		GroupNum:       in.GroupOrderNo,
		PersonGroupNum: groupOrderNo,
		TotalPrice:     price * float64(in.Num),
		GroupGid:       group.GroupGid,
		People:         group.People,
		Price:          group.Price,
		StartTime:      group.StartTime,
		EndTime:        group.EndTime,
		KId:            1, // 1表示团员
		Status:         1,
		GroupType:      group.GroupType, // 继承主拼团的类型
	}

	if err := joinGroup.CreateGroupBuying(); err != nil {
		return nil, errors.New("参与拼团失败")
	}

	// 9. 扣减库存
	groupPGoods.Stock -= uint64(in.Num)
	if err := groupPGoods.UpdateStock(); err != nil {
		return nil, errors.New("扣减库存失败")
	}

	// 10. 检查是否达到拼团人数
	var newCount int64
	if err := joinGroup.GetGroupByPeople(newCount); err != nil {
		return nil, errors.New("获取拼团人数失败")
	}
	if newCount >= int64(group.People) {
		// 更新拼团状态为已完成
		err := UpdateGroupStatus(in.GroupOrderNo, 2)
		if err != nil {
			return nil, errors.New("更新拼团状态失败")
		}
	}

	return &__.JoinGroupPResp{
		Message:         "参与拼团成功",
		GroupId:         int64(joinGroup.Id),
		PersonalOrderNo: personalOrderNo,
		GroupOrderNo:    groupOrderNo,
	}, nil
}

// GetGroupDetail 获取拼团详情
func GetGroupDetail(in *__.GroupDetailReq) (*__.GroupDetailResp, error) {
	// 查询拼团详情
	var group models.GroupBuying
	group.Id = uint64(in.GroupId)
	if err := group.GetGroupRetail(); err != nil {
		return nil, errors.New("查询拼团详情失败")
	}
	// 查询拼团成员
	var members []models.GroupBuying
	if err := config.DB.Where("group_num = ?", group.GroupNum).Find(&members).Error; err != nil {
		return nil, errors.New("查询拼团成员失败")
	}

	// 构建响应
	resp := &__.GroupDetailResp{
		GroupId:   in.GroupId,
		GroupNum:  group.GroupNum,
		GoodsId:   int64(group.GroupGid),
		TotalNum:  int64(group.People),
		JoinedNum: int64(len(members)),
		StartTime: group.StartTime,
		EndTime:   group.EndTime,
		Status:    int64(group.Status),
		GroupType: uint64(group.GroupType), // 拼团类型
	}

	// 添加拼团成员信息
	for _, member := range members {
		resp.Members = append(resp.Members, &__.GroupMember{
			UserId:   int64(member.UserId),
			IsLeader: member.KId == 0,
		})
	}

	return resp, nil
}

// CheckJoin资格 检查用户参与拼团资格
func CheckJoinEligibility(userId, goodsId int64) (bool, error) {
	// 1. 检查用户是否已达到限购数量
	var count int64
	// 根据用户ID和商品ID查询
	config.DB.Model(&models.GroupBuying{}).Where("user_id = ? AND group_gid = ?", userId, goodsId).Count(&count)

	// 获取商品的限购数量
	var goods models.GroupPGoods
	goods.Id = uint64(goodsId)
	if err := config.DB.Where("id = ?", goodsId).First(&goods).Error; err != nil {
		return false, errors.New("商品不存在")
	}

	if count >= int64(goods.LimitPerson) {
		return false, errors.New("已达到限购数量")
	}

	////2. 检查活动是否在有效期内
	//now := time.Now()
	//startTime, _ := time.Parse("2006-01-02 15:04:05", goods.StartTime)
	//endTime, _ := time.Parse("2006-01-02 15:04:05", goods.EndTime)
	//
	//if now.Before(startTime) || now.After(endTime) {
	//	return false, errors.New("活动不在有效期内")
	//}

	// 3. 检查库存
	if goods.Stock <= 0 {
		return false, errors.New("商品库存不足")
	}

	return true, nil
}

// GenerateOrderNo 生成订单号
func GenerateOrderNo(userId int64) (string, string, error) {
	t := time.Now()
	// 生成个人订单号
	personalOrderNo := fmt.Sprintf("PO%d%d%d%d",
		t.Year(), t.Month(), t.Day(),
		userId, rand.Intn(10000))

	// 生成拼团公共订单号
	groupOrderNo := fmt.Sprintf("GO%d%d%d%d",
		t.Year(), t.Month(), t.Day(),
		userId, rand.Intn(10000))

	return personalOrderNo, groupOrderNo, nil
}

// UpdateGroupStatus 更新拼团状态
func UpdateGroupStatus(groupNum string, status int64) error {
	return config.DB.Model(&models.GroupBuying{}).Where("group_num = ?", groupNum).Update("status", status).Error
}

// HandlePaymentCallback 处理支付回调
func HandlePaymentCallback(in *__.PaymentCallbackReq) (*__.PaymentCallbackResp, error) {
	// 1. 验证回调数据的有效性

	// 2. 根据支付结果更新订单状态
	if in.Status == 1 { // 支付成功
		// 更新拼团状态
		// 检查是否达到拼团人数，如果达到则更新为已完成
		var count int64
		config.DB.Model(&models.GroupBuying{}).Where("group_num = ? AND k_id != 0", in.GroupNum).Count(&count)

		var group models.GroupBuying
		config.DB.Where("group_num = ? AND k_id = 0", in.GroupNum).First(&group)

		if count >= int64(group.People-1) { // 团长不算在人数内
			err := UpdateGroupStatus(in.GroupNum, 2)
			if err != nil {
				return nil, errors.New("更新拼团状态失败")
			} // 设置为已完成
		}
	} else { // 支付失败
		// 处理支付失败逻辑，如取消订单、释放库存等
	}

	return &__.PaymentCallbackResp{Success: true}, nil
}

// GetUserGroupRecords 获取用户参与的拼团记录
func GetUserGroupRecords(userId int64, page, pageSize int64) ([]*__.GroupRecord, error) {
	var records []models.GroupBuying
	var resp []*__.GroupRecord

	// 查询用户参与的拼团记录
	if err := config.DB.Where("user_id = ?", userId).Offset(int((page - 1) * pageSize)).Limit(int(pageSize)).Find(&records).Error; err != nil {
		return nil, err
	}

	// 转换为响应格式
	for _, record := range records {
		resp = append(resp, &__.GroupRecord{
			GroupId:   int64(record.Id),
			GroupNum:  record.GroupNum,
			GoodsId:   int64(record.GroupGid),
			Status:    int64(record.Status),
			JoinTime:  record.CreatedAt.Format("2006-01-02 15:04:05"),
			IsLeader:  record.KId == 0,
			GroupType: uint64(record.GroupType), // 拼团类型
		})
	}

	return resp, nil
}

// GetUserGroupRecordsTotal 获取用户拼团记录总数
func GetUserGroupRecordsTotal(userId int64) (int64, error) {
	var total int64
	err := config.DB.Model(&models.GroupBuying{}).Where("user_id = ?", userId).Count(&total).Error
	return total, err
}
